﻿Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Runtime.Serialization
Imports System.Xml.Serialization
Imports CQRSAzure.Tools
Imports Microsoft.VisualBasic
''' <summary>
''' Class to describe an aggregate for code generation
''' </summary>
''' <remarks>
''' Each aggregate must have an unique name
''' </remarks>
<DataContract(Name:=NameOf(AggregateModel))>
<XmlType("aggregateModel", AnonymousType:=False)>
<Serializable>
Public NotInheritable Class AggregateModel
    Implements System.ComponentModel.INotifyPropertyChanged

    <DataMember(Name:=NameOf(Name))>
    Private ReadOnly m_name As String
    ''' <summary>
    ''' The unique name by which the aggregate model is known
    ''' </summary>
    <XmlAttribute(AttributeName:="AggregateName")>
    Public ReadOnly Property Name As String
        Get
            Return m_name
        End Get
    End Property

    <DataMember(Name:=NameOf(KeyType))>
    Private m_key As SimpleKeyDataType.KeyDataType
    <XmlAttribute(AttributeName:="KeyDataType")>
    Public Property KeyType As SimpleKeyDataType.KeyDataType
        Get
            Return m_key
        End Get
        Set(value As SimpleKeyDataType.KeyDataType)
            If (m_key <> value) Then
                m_key = value
                OnPropertyChanged(NameOf(KeyType))
            End If
        End Set
    End Property

    <DataMember(Name:=NameOf(KeyName))>
    Private m_keyName As String = "Key"
    ''' <summary>
    ''' The name by which the property which provides the unique key for this aggregate is known
    ''' </summary>
    ''' <remarks>
    ''' This defaults to "Key" if there is no meaningful business key name
    ''' </remarks>
    <XmlAttribute(AttributeName:="KeyName")>
    Public Property KeyName As String
        Get
            Return m_keyName
        End Get
        Set(value As String)
            If Not (m_keyName.Equals(value)) Then
                m_keyName = value
                OnPropertyChanged(NameOf(KeyName))
            End If
        End Set
    End Property

    Private m_events As New System.Collections.Generic.Dictionary(Of String, EventModel)
    ''' <summary>
    ''' The set of events connected to this specific aggregate 
    ''' </summary>
    Public ReadOnly Property Events As Dictionary(Of String, EventModel)
        Get
            Return m_events
        End Get
    End Property

    ''' <summary>
    ''' Adds a new event of the given name to this aggregate
    ''' </summary>
    ''' <param name="eventName">
    ''' The unique name to use for the event
    ''' </param>
    ''' <remarks>
    ''' The event name must be unique within any given aggregate
    ''' </remarks>
    Public Sub AddNewEvent(ByVal eventName As String)
        If (m_events.ContainsKey(eventName)) Then
            Throw New EventNameExistsException(eventName)
        Else
            m_events.Add(eventName, New EventModel(eventName))
            'Raise an event to notify that a new event was added
            OnEventModelAdded(eventName)
            OnPropertyChanged(NameOf(Events))
        End If
    End Sub

    Private Sub OnEventModelAdded(ByVal NewEventName As String)
        RaiseEvent EventModelAdded(Me, New EventModelEventArgs(NewEventName))
    End Sub
    Public Event EventModelAdded(ByVal sender As Object, ByVal e As EventModelEventArgs)

    Public Sub DeleteEvent(ByVal eventName As String)
        If (m_events.ContainsKey(eventName)) Then
            m_events.Remove(eventName)
            'Raise an event that the event model was removed
            OnEventModelRemoved(eventName)
            OnPropertyChanged(NameOf(Events))
        End If
    End Sub

    Private Sub OnEventModelRemoved(ByVal RemovedEventName As String)
        RaiseEvent EventModelRemoved(Me, New EventModelEventArgs(RemovedEventName))
    End Sub
    Public Event EventModelRemoved(ByVal sender As Object, ByVal e As EventModelEventArgs)

    Private m_projections As New System.Collections.Generic.Dictionary(Of String, ProjectionModel)
    Public ReadOnly Property Projections As System.Collections.Generic.Dictionary(Of String, ProjectionModel)
        Get
            Return m_projections
        End Get
    End Property

    Public Sub AddNewProjection(ByVal projectionName As String)
        If (m_projections.ContainsKey(projectionName)) Then
            Throw New ProjectionNameExistsException(projectionName)
        Else
            m_projections.Add(projectionName, New ProjectionModel(projectionName))
            OnProjectionAdded(projectionName)
            OnPropertyChanged(NameOf(Projections))
        End If
    End Sub

    Private Sub OnProjectionAdded(ByVal newProjectionName As String)
        RaiseEvent ProjectionAdded(Me, New ProjectionModelEventArgs(newProjectionName))
    End Sub
    Public Event ProjectionAdded(ByVal sender As Object, ByVal e As ProjectionModelEventArgs)

    Public Sub RemoveProjection(ByVal projectionName As String)
        If (m_projections.ContainsKey(projectionName)) Then
            m_projections.Remove(projectionName)
            'Raise a projection removed event
            OnProjectionRemoved(projectionName)
            OnPropertyChanged(NameOf(Projections))
        End If
    End Sub

    Private Sub OnProjectionRemoved(ByVal projectionName As String)
        RaiseEvent ProjectionRemoved(Me, New ProjectionModelEventArgs(projectionName))
    End Sub
    Public Event ProjectionRemoved(ByVal sender As Object, ByVal e As ProjectionModelEventArgs)

#Region "Serialisation"

    Public Sub GetObjectData(info As SerializationInfo, context As StreamingContext)
        If (info IsNot Nothing) Then
            info.AddValue(NameOf(Name), m_name)
            info.AddValue(NameOf(KeyType), m_key)
            info.AddValue(NameOf(KeyName), m_keyName)
        End If
    End Sub

#End Region

#Region "Public constructors"
    ''' <summary>
    ''' Empty constructor for serialisation
    ''' </summary>
    Public Sub New()

    End Sub

    Public Sub New(ByVal InitialAggregateName As String)
        m_name = InitialAggregateName
    End Sub

    Public Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
        If (info IsNot Nothing) Then
            m_name = info.GetString(NameOf(Name))
            m_key = info.GetValue(NameOf(KeyType), GetType(KeyDataType))
            m_keyName = info.GetString(NameOf(KeyName))
        End If
    End Sub
#End Region


#Region "Property Change Notification"
    Public Sub OnPropertyChanged(ByVal propertyName As String)

        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))

    End Sub
    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
#End Region

End Class
